/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       character.h
 * Author:     twoja stara
 * Created on: 201-04-02
 *
 **********************************************************************************************************************/

#ifndef CHARACTER_H_
#define CHARACTER_H_

#include "actor.h"
#include <NxControllerManager.h>
#include <NxController.h>
#include <NxBoxController.h>
#include <NxCapsuleController.h>

namespace mGameEngine
{
namespace Physics
{

/**
 * Physics controlled character.
 * TODO
 */
class Character : public Actor, protected NxUserControllerHitReport
{
protected:
    /**
     * PhysX controllers manager.
     */
    static NxControllerManager *_manager;

    /**
     * 
     */
    float _height;
    
    /**
     * 
     */
    float _width;
    
    /**
     * 
     */
    float _speed;
    
    /**
     * 
     */
    float _acc;
    
    /**
     * 
     */
    float _dec;
    
    /**
     * 
     */
    float _jump;
    
    /**
     * 
     */
    float _jumpControl;
    
    /**
     * 
     */
    float _step;
    
    /**
     * 
     */
    float _slope;

    /**
     * 
     */
    bool _floor;
    
    /**
     * 
     */
    Vector3 _vel;
    
    /**
     * PhysX controller.
     */
    mutable NxCapsuleController *_controller;

public:
    /**
     * Create PhysX actor for character.
     * @param joint joint.
     * @return PhysX actor for joint.
     */
    virtual NxActor *_createJointActor(Joint *joint) const;

protected:
    /**
     * PhysX shape hit callback.
     * @param hit hit data.
     * @return hit action.
     */
    virtual NxControllerAction onShapeHit(const NxControllerShapeHit& hit);

    /**
     * PhysX controller hit callback.
     * @param hit hit data.
     * @return hit action.
     */
    virtual NxControllerAction onControllerHit(const NxControllersHit& hit);

public:
    /**
     *
     */
    Character();

    /**
     *
     */
    virtual ~Character();

    /**
     * 
     */
    float getWidth() const
    {
        return _width;
    }

    /**
     * 
     */
    void setWidth(float width);

    /**
     *
     * @return 
     */
    float getHeight() const
    {
        return _height;
    }

    /**
     *
     * @param height
     */
    void setHeight(float height);

    /**
     * @return
     */
    float getSpeed() const
    {
        return _speed;
    }

    /**
     * @param speed
     */
    void setSpeed(float speed);

    /**
     * @return
     */
    float getAcceleration() const
    {
        return _acc;
    }

    /**
     * @param acc
     */
    void setAcceleration(float acc);

    /**
     * @return
     */
    float getAccelerationTime() const
    {
        return _speed / _acc;
    }

    /**
     * @param accTime
     */
    void setAccelerationTime(float accTime)
    {
        setAcceleration(_speed/accTime);
    }

    /**
     * @return
     */
    float getDeceleration() const
    {
        return _dec;
    }

    /**
     * @param dec
     */
    void setDecelartion(float dec);

    /**
     * @return 
     */
    float getDecelerationTime() const
    {
        return _speed / _dec;
    }

    /**
     * @param decTime
     */
    void setDecelerationTime(float decTime)
    {
        setDecelartion(_speed/decTime);
    }

    /**
     * @return 
     */
    float getJumpHeight() const
    {
        return _jump;
    }

    /**
     * @param jump
     */
    void setJumpHeight(float jump);

    /**
     * @return
     */
    float getJumpControl() const
    {
        return _jumpControl;
    }

    /**
     * @param jumpcontrol
     */
    void setJumpControl(float jumpControl);

    /**
     * @return
     */
    float getStepHeight() const
    {
        return _step;
    }

    /**
     * @param step
     */
    void setStepHeight(float step);

    /**
     * @return
     */
    float getSlope() const
    {
        return _slope;
    }

    /**
     * @param slope
     */
    void setSlope(float slope);

    /**
     * Put force/momentum to character. This has no effect on character.
     * @param force force vector.
     * @param radius radius at which force is put.
     */
    virtual void putForce(const Vector3 &force, const Vector3 &radius = Vector3());

    /**
     * Put force/momentum impulse to character. This has no effect on character.
     * @param impulse force vector.
     * @param radius radius at which force is put.
     */
    virtual void putImpulse(const Vector3 &impulse, const Vector3 &radius = Vector3());

    /**
     * Put acceleration to character. This has no effect on character.
     * @param acc acceleration vector.
     * @param radius radius at which acceleration is put.
     */
    virtual void putAcceleration(const Vector3 &acc, const Vector3 &radius = Vector3());

    /**
     * @param dt
     * @param forward
     * @param backward
     * @param left
     * @param right
     * @param yaw
     * @param jump
     */
    void update(float dt, bool forward, bool backward, bool left, bool right, float yaw, bool jump);

    /**
     * Create actor on PhysX scene.
     * @param scene PhysX scene.
     */
    virtual void create(NxScene *scene) const;

    /**
     * Get actor transformation.
     * @return actor transformation.
     */
    virtual Matrix4x4 getTransformation() const;

    /**
     * Set actor transformation.
     * @param t transformation.
     */
    virtual void setTransformation(const Matrix4x4 &t);

    /**
     * Get actor point linear velocity.
     * @param p actor point.
     */
    virtual Vector3 getPointVelocity(const Vector3 &p);
};

}
}

#endif // CHARACTER_H_
